package com.data.hijack.util;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author husq
 */
public final class FileUtils {
    private FileUtils() {
        throw new IllegalStateException();
    }

    /**
     *
     * @param outputDir
     * @param subDir
     */
    public static void createDirectory(String outputDir, String subDir) {
        File file = new File(outputDir);
        if (!(subDir == null || subDir.trim().equals(""))) {
            file = new File(outputDir + File.separator + subDir);
        }
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     *
     * @param file
     */
    public static void deleteDirectory(File file) {
        if (file.isFile()) {
            file.delete();
        } else {
            File list[] = file.listFiles();
            if (list != null) {
                for (File f : list) {
                    deleteDirectory(f);
                }
                file.delete();
            }
        }
    }

    /**
     *
     * @param dir
     */
    public static void deleteAllFile(File dir) {
        if (dir.isDirectory()) {
            String[] fileList = dir.list();
            for (int i = 0; i < fileList.length; i++) {
                File file = new File(dir.getAbsolutePath() + File.separator + fileList[i]);
                if (file.isDirectory()) {
                    deleteAllFile(file);
                } else {
                    file.delete();
                }
            }
        }
    }

    public static byte[] readFromFile(String path) throws IOException {
        return readFromFile(null, path, 0);
    }

    public static byte[] readFromFile(String path, int capacity) throws IOException {
        return readFromFile(null, path, capacity);
    }

    public static byte[] readFromFile(String filename, String path, int capacity) throws IOException {
        if (Objects.nonNull(filename)) {
            path += File.separator + filename;
        }

        BigFileContentReader readFile = null;
        try {
            readFile = new BigFileContentReader(path);
            byte[] b = readFile.read(capacity);

            return b;
        } finally {
            if (Objects.nonNull(readFile)) {
                readFile.clear();
            }
        }
    }

    /**
     * 
     * @param path
     * @param delimiter
     * @return
     * @throws Exception
     */
    public static String readFromFile(String path, String delimiter) throws Exception {
        return readFromFile(null, path, delimiter);
    }

    /**
     *
     * @param filename
     * @param path
     * @return
     * @throws Exception
     */
    public static String readFromFile(String filename, String path, String delimiter) throws Exception {
        if (Objects.nonNull(filename)) {
            path += File.separator + filename;
        }

        BigFileContentReader readFile = new BigFileContentReader(path);

        String line = null;
        StringBuilder detailStrBuilder = new StringBuilder(32);
        try {
            while ((line = readFile.readLine()) != null) {
                detailStrBuilder.append(line).append(delimiter);
            }
        } finally {
            readFile.clear();
        }

        return detailStrBuilder.toString();
    }

    /**
     * 
     * @param filename
     * @param path
     * @param lineCapacity
     * @param delimiter
     * @param charset
     * @return
     * @throws Exception
     */
    public static String readFromFile(String filename, String path, int lineCapacity, String delimiter, String charset)
        throws Exception {
        path += File.separator + filename;
        BigFileContentReader readFile = new BigFileContentReader(path);

        String line = null;
        StringBuilder detailStrBuilder = new StringBuilder(32);
        try {
            while ((line = readFile.readLine(lineCapacity, delimiter.getBytes(charset), charset)) != null) {
                detailStrBuilder.append(line).append(delimiter);
            }
        } finally {
            readFile.clear();
        }

        return detailStrBuilder.toString();
    }

    public static boolean writeToFile(String filename, String path, String content) throws Exception {
        String charset = Charset.defaultCharset().name();
        return writeToFile(filename, path, content, charset);
    }

    public static boolean writeToFile(String filename, String path, String content, String charset) throws Exception {
        return writeToFile(filename, path, content, charset, false);
    }

    /**
     * 
     * @param filename
     * @param path
     * @param content
     * @param charset
     * @param append
     * @return
     * @throws Exception
     */
    public static boolean writeToFile(String filename, String path, String content, String charset, boolean append)
        throws Exception {
        if (StringUtils.isBlank(charset)) {
            charset = "GBK";
        }

        createDirectory(path, null);
        String separator = File.separator;
        if (!path.startsWith(separator)) {
            path += separator;
        }
        path += filename;
        if (path.endsWith(separator)) {
            path += separator;
        }

        if (!append) {
            deleteDirectory(new File(path));
        }

        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path, append), charset));
            writer.write(content);
            writer.flush();

            return true;
        } catch (Exception e) {
            throw new Exception(e);
        } finally {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 
     * @param filename
     * @param suffix
     * @param clazz
     * @return
     * @throws IOException
     */
    public static File getFile(String filename, String suffix, Class<?> clazz) throws IOException {
        File[] files = findPathMatchingResources(filename, clazz);
        filename += "." + suffix;

        return iterate(files, filename);
    }

    public static String getFilePath(String filename, String suffix, Class<?> clazz) throws IOException {
        File f = getFile(filename, suffix, clazz);
        if (Objects.nonNull(f)) {
            return f.getPath();
        }

        return null;
    }

    /**
     * 
     * @param filename
     * @param suffix
     * @param clazz
     * @param classPath
     * @return
     * @throws IOException
     */
    public static File getFile(String filename, String suffix, Class<?> clazz, String classPath) throws IOException {
        File[] files = findPathMatchingResources(filename, clazz, classPath);
        filename += "." + suffix;

        return iterate(files, filename);
    }

    public static String getFilePath(String filename, String suffix, Class<?> clazz, String classPath)
        throws IOException {
        File f = getFile(filename, suffix, clazz, classPath);
        if (Objects.nonNull(f)) {
            return f.getPath();
        }

        return null;
    }

    /**
     * 
     * @param basename
     * @param clazz
     * @return
     * @throws IOException
     */
    public static File[] findPathMatchingResources(String basename, Class<?> clazz) throws IOException {
        return findPathMatchingResources(basename, clazz, null);
    }

    /**
     * 
     * @param basename
     * @param clazz
     * @param classPath
     * @return
     * @throws IOException
     */
    public static File[] findPathMatchingResources(String basename, Class<?> clazz, String classPath)
        throws IOException {
        String path = BeanUtils.getClassLoader(clazz).getResource("").getPath();

        if (!path.startsWith("/")) {
            path += "/";
        }
        if (!StringUtils.isBlank(classPath)) {
            String cp = classPath.replaceAll("\\.", "/");
            if (!path.endsWith("/")) {
                path += "/";
            }
            path += cp;
        }
        path = StringUtils.replace(path, File.separator, "/");

        File[] files = readFileList(basename, path);

        return files;
    }

    public static File[] readFileList(final String pattern, String path) {
        List<File> fnameContainer = new ArrayList<File>();
        readFileList(path, pattern, fnameContainer);
        return (File[])fnameContainer.toArray(new File[0]);
    }

    public static String getFileName(File f) {
        String filepath = f.getPath();
        filepath = StringUtils.replace(filepath, File.separator, "/");
        List<String> splitPath = TextUtils.split(filepath, 47);
        return splitPath.get(splitPath.size() - 1);
    }

    /**
     * 
     * @param base
     * @return
     */
    public static String getFileName(String base) {
        return base + DateUtils.getDate("yyyyMMddHHmmss") + StringUtils.getSerialNo(6);
    }

    /**
     * 
     * @param filename
     * @return
     * @throws Exception
     */
    public static String encode2Base64(String filename) throws Exception {
        File file = new File(filename);
        return encode2Base64(file);
    }

    /**
     * 
     * @param file
     * @return
     * @throws Exception
     */
    public static String encode2Base64(File file) throws Exception {
        FileInputStream fis = null;
        byte[] buffer = null;
        try {
            fis = new FileInputStream(file);
            buffer = new byte[(int)fis.available()];
            fis.read(buffer);
        } catch (FileNotFoundException e) {
            throw e;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            AppUtils.safeClose(fis);
        }

        return StringUtils.getBase64(buffer);
    }

    /**
     * 
     * @param base64File
     * @param path
     * @param filename
     * @throws Exception
     */
    public static void decoderBase64(String base64File, String path, String filename) throws Exception {
        createDirectory(path, null);
        String destFile = path + File.separator + filename;
        deleteDirectory(new File(destFile));

        byte[] buffer = null;
        FileOutputStream fos = null;
        try {
            buffer = StringUtils.decodeBase64(base64File);
            fos = new FileOutputStream(destFile);
            fos.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            AppUtils.safeClose(fos);
        }
    }

    private static void readFileList(String dir, final String pattern, List<File> fileContainer) {
        File fdir = new File(dir);
        if (fdir.isDirectory()) {
            String[] files = fdir.list(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    final File f = new File(dir + File.separator + name);
                    if (f.isDirectory()) {
                        return true;
                    }

                    String fname = f.getName();
                    if (fname.contains(pattern) && f.length() > 0) {
                        return true;
                    }

                    return false;
                }
            });

            for (String name : files) {
                dir = fdir.getAbsolutePath() + File.separator + name;
                readFileList(dir, pattern, fileContainer);
            }
        } else {
            fileContainer.add(fdir);
        }
    }

    private static File iterate(File[] files, String filename) {
        File file = null;
        for (File f : files) {
            String fn = f.getName();
            if (null != fn && fn.equals(filename)) {
                file = f;
                break;
            }
        }

        return file;
    }
}
